home *** CD-ROM | disk | FTP | other *** search
- #!/usr/bin/python
-
- # $Header$
- # This program is licensed under the GPL, version 2
-
- import os,string,sys
- sys.path.insert(0, "/usr/lib/gentoolkit/pym")
- sys.path.insert(0, "/usr/lib/portage/pym")
- from output import *
- from getopt import getopt,GetoptError
-
- __program__ = "glsa-check"
- __author__ = "Marius Mauch <genone@gentoo.org>"
- __version__ = "0.6"
-
- optionmap = [
- ["-l", "--list", "list all unapplied GLSA"],
- ["-d", "--dump", "--print", "show all information about the given GLSA"],
- ["-t", "--test", "test if this system is affected by the given GLSA"],
- ["-p", "--pretend", "show the necessary commands to apply this GLSA"],
- ["-f", "--fix", "try to auto-apply this GLSA (experimental)"],
- ["-i", "--inject", "inject the given GLSA into the checkfile"],
- ["-n", "--nocolor", "disable colors (option)"],
- ["-h", "--help", "show this help message"],
- ["-V", "--version", "some information about this tool"],
- ["-v", "--verbose", "print more information (option)"],
- ["-c", "--cve", "show CAN ids in listing mode (option)"],
- ]
-
- # print a warning as this is beta code (but proven by now, so no more warning)
- #sys.stderr.write("WARNING: This tool is completely new and not very tested, so it should not be\n")
- #sys.stderr.write("used on production systems. It's mainly a test tool for the new GLSA release\n")
- #sys.stderr.write("and distribution system, it's functionality will later be merged into emerge\n")
- #sys.stderr.write("and equery.\n")
- #sys.stderr.write("Please read http://www.gentoo.org/proj/en/portage/glsa-integration.xml\n")
- #sys.stderr.write("before using this tool AND before reporting a bug.\n\n")
-
- # option parsing
- args = []
- params = []
- try:
- args, params = getopt(sys.argv[1:], "dplfchinvVtc", \
- ["dump", "print", "list", "pretend", "fix", "inject", "help", "info", "version", "test", "nocolor", "cve"])
- args = [a for a,b in args]
-
- for option in ["--nocolor", "-n"]:
- if option in args:
- nocolor()
- args.remove(option)
-
- verbose = False
- for option in ["--verbose", "-v"]:
- if option in args:
- verbose = True
- args.remove(option)
-
- list_cve = False
- for option in ["--cve", "-c"]:
- if option in args:
- list_cve = True
- args.remove(option)
-
- # sanity checking
- if len(args) <= 0:
- sys.stderr.write("no option given: what should I do ?\n")
- mode="help"
- elif len(args) > 1:
- sys.stderr.write("please use only one command per call\n")
- mode = "help"
- else:
- # in what mode are we ?
- args = args[0]
- for m in optionmap:
- if args in [o for o in m[:-1]]:
- mode = m[1][2:]
-
- except GetoptError, e:
- sys.stderr.write("unknown option given: ")
- sys.stderr.write(str(e)+"\n")
- mode = "help"
-
- # we need a set of glsa for most operation modes
- if len(params) <= 0 and mode in ["fix", "test", "pretend", "dump", "inject"]:
- sys.stderr.write("\nno GLSA given, so we'll do nothing for now. \n")
- sys.stderr.write("If you want to run on all GLSA please tell me so \n")
- sys.stderr.write("(specify \"all\" as parameter)\n\n")
- mode = "help"
- elif len(params) <= 0 and mode == "list":
- params.append("new")
-
- # show help message
- if mode == "help":
- sys.stderr.write("\nSyntax: glsa-check <option> [glsa-list]\n\n")
- for m in optionmap:
- sys.stderr.write(m[0] + "\t" + m[1] + " \t: " + m[-1] + "\n")
- for o in m[2:-1]:
- sys.stderr.write("\t" + o + "\n")
- sys.stderr.write("\nglsa-list can contain an arbitrary number of GLSA ids, \n")
- sys.stderr.write("filenames containing GLSAs or the special identifiers \n")
- sys.stderr.write("'all', 'new' and 'affected'\n")
- sys.exit(1)
-
- # we need root priviledges for write access
- if mode in ["fix", "inject"] and os.geteuid() != 0:
- sys.stderr.write("\nThis tool needs root access to "+mode+" this GLSA\n\n")
- sys.exit(2)
-
- # show version and copyright information
- if mode == "version":
- sys.stderr.write("\n"+ __program__ + ", version " + __version__ + "\n")
- sys.stderr.write("Author: " + __author__ + "\n")
- sys.stderr.write("This program is licensed under the GPL, version 2\n\n")
- sys.exit(0)
-
- # delay this for speed increase
- from glsa import *
-
- glsaconfig = checkconfig(portage.config(clone=portage.settings))
-
- # Check that we really have a glsa dir to work on
- if not (os.path.exists(glsaconfig["GLSA_DIR"]) and os.path.isdir(glsaconfig["GLSA_DIR"])):
- sys.stderr.write(red("ERROR")+": GLSA_DIR %s doesn't exist. Please fix this.\n" % glsaconfig["GLSA_DIR"])
- sys.exit(1)
-
- # build glsa lists
- completelist = get_glsa_list(glsaconfig["GLSA_DIR"], glsaconfig)
-
- if os.access(glsaconfig["CHECKFILE"], os.R_OK):
- checklist = [line.strip() for line in open(glsaconfig["CHECKFILE"], "r").readlines()]
- else:
- checklist = []
- todolist = [e for e in completelist if e not in checklist]
-
- glsalist = []
- if "new" in params:
- glsalist = todolist
- params.remove("new")
- if "all" in params:
- glsalist = completelist
- params.remove("all")
- if "affected" in params:
- # maybe this should be todolist instead
- for x in completelist:
- try:
- myglsa = Glsa(x, glsaconfig)
- except (GlsaTypeException, GlsaFormatException), e:
- if verbose:
- sys.stderr.write(("invalid GLSA: %s (error message was: %s)\n" % (x, e)))
- continue
- if myglsa.isVulnerable():
- glsalist.append(x)
- params.remove("affected")
-
- # remove invalid parameters
- for p in params[:]:
- if not (p in completelist or os.path.exists(p)):
- sys.stderr.write(("(removing %s from parameter list as it isn't a valid GLSA specification)\n" % p))
- params.remove(p)
-
- glsalist.extend([g for g in params if g not in glsalist])
-
- # list short information for given or new GLSA
- if mode == "list":
- sys.stderr.write(white("[A]")+" means this GLSA was already applied,\n")
- sys.stderr.write(green("[U]")+" means the system is not affected and\n")
- sys.stderr.write(red("[N]")+" indicates that the system might be affected.\n\n")
-
- for myid in glsalist:
- try:
- myglsa = Glsa(myid, glsaconfig)
- except (GlsaTypeException, GlsaFormatException), e:
- if verbose:
- sys.stderr.write(("invalid GLSA: %s (error message was: %s)\n" % (myid, e)))
- continue
- if myglsa.isApplied():
- status = "[A]"
- color = white
- elif myglsa.isVulnerable():
- status = "[N]"
- color = red
- else:
- status = "[U]"
- color = green
- sys.stdout.write(color(myglsa.nr) + " " + color(status) + " " + myglsa.title + " (")
- for pkg in myglsa.packages.keys()[:3]:
- sys.stdout.write(" " + pkg + " ")
- if len(myglsa.packages) > 3:
- sys.stdout.write("... ")
- sys.stdout.write(")")
- if list_cve:
- sys.stdout.write(" "+(",".join([r[:13] for r in myglsa.references if r[:4] == "CAN-"])))
- sys.stdout.write("\n")
- sys.exit(0)
-
- # dump, fix, inject and fix are nearly the same code, only the glsa method call differs
- if mode in ["dump", "fix", "inject", "pretend"]:
- for myid in glsalist:
- try:
- myglsa = Glsa(myid, glsaconfig)
- except (GlsaTypeException, GlsaFormatException), e:
- if verbose:
- sys.stderr.write(("invalid GLSA: %s (error message was: %s)\n" % (myid, e)))
- continue
- if mode == "dump":
- myglsa.dump()
- elif mode == "fix":
- sys.stdout.write("fixing "+myid+"\n")
- mergelist = myglsa.getMergeList()
- for pkg in mergelist:
- sys.stdout.write(">>> merging "+pkg+"\n")
- # using emerge for the actual merging as it contains the dependency
- # code and we want to be consistent in behaviour. Also this functionality
- # will be integrated in emerge later, so it shouldn't hurt much.
- emergecmd = "emerge --oneshot " + glsaconfig["EMERGE_OPTS"] + " =" + pkg
- if verbose:
- sys.stderr.write(emergecmd+"\n")
- exitcode = os.system(emergecmd)
- if exitcode:
- sys.exit(exitcode)
- myglsa.inject()
- elif mode == "pretend":
- sys.stdout.write("Checking GLSA "+myid+"\n")
- mergelist = myglsa.getMergeList()
- if mergelist:
- sys.stdout.write("The following updates will be performed for this GLSA:\n")
- for pkg in mergelist:
- # we simplify a bit here
- oldver = portage.db["/"]["vartree"].dbapi.match(portage.dep_getkey(pkg))[-1]
- oldver = oldver[len(portage.dep_getkey(oldver))+1:]
- sys.stdout.write(" " + pkg + " (" + oldver + ")\n")
- else:
- sys.stdout.write("Nothing to do for this GLSA\n")
- elif mode == "inject":
- sys.stdout.write("injecting " + myid + "\n")
- myglsa.inject()
- sys.stdout.write("\n")
- sys.exit(0)
-
- # test is a bit different as Glsa.test() produces no output
- if mode == "test":
- outputlist = []
- for myid in glsalist:
- try:
- myglsa = Glsa(myid, glsaconfig)
- except (GlsaTypeException, GlsaFormatException), e:
- if verbose:
- sys.stderr.write(("invalid GLSA: %s (error message was: %s)\n" % (myid, e)))
- continue
- if myglsa.isVulnerable():
- outputlist.append(myglsa.nr)
- if len(outputlist) > 0:
- sys.stderr.write("This system is affected by the following GLSAs:\n")
- for g in outputlist:
- sys.stdout.write(g)
- if verbose:
- sys.stdout.write(" ( " + myglsa.title + " )\n")
- else:
- sys.stdout.write("\n")
- else:
- sys.stderr.write("This system is not affected by any of the listed GLSAs\n")
- sys.exit(0)
-
- # something wrong here, all valid paths are covered with sys.exit()
- sys.stderr.write("nothing more to do\n")
- sys.exit(2)
-